package com.java.common.pay.wxpay.utils;

import com.java.common.pay.wxpay.conf.WxConfig;
import com.java.common.utils.tool.IpUtils;
import com.java.common.utils.tool.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.security.KeyStore;
import java.util.SortedMap;
import java.util.TreeMap;

public class WxPayTool {

    private static final Logger log = LoggerFactory.getLogger(WxPayTool.class);

    /**
     * 方法名：refund
     * 详述：微信支付退款接口
     *
     * @param appid         邮件中的APPID
     * @param mch_id        微信支付商户号
     * @param out_trade_no  订单号
     * @param out_refund_no 退款单号
     * @param total_fee     订单总额
     * @param refund_fee    退款金额
     * @return
     */
    public static String refund(String appid, String mch_id, String out_trade_no, String out_refund_no, int total_fee, int refund_fee) {
        try {
            StringBuilder sb = new StringBuilder();
            SortedMap<String, Object> sp = new TreeMap<String, Object>();
            sp.put("appid", appid);
            sp.put("mch_id", mch_id);
            sp.put("nonce_str", MD5Tool.encryptString(System.currentTimeMillis() / 1000 + ""));
            sp.put("out_trade_no", out_trade_no);
            sp.put("out_refund_no", out_refund_no);
            sp.put("total_fee", total_fee);
            sp.put("refund_fee", refund_fee);
            sp.put("sign", SignTool.signApp(sp));
            String reqXML = XMLTool.mapToXML(sp);
            log.info("--- refund() reqXML:\n" + reqXML, WxPayTool.class);
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            FileInputStream instream = new FileInputStream(new File(WxConfig.path_cert));
            try {
                keyStore.load(instream, mch_id.toCharArray());
            } finally {
                instream.close();
            }
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext,
                    new String[]{"TLSv1"},
                    null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .build();
            try {
                HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
                //HttpEntity reqEntity = MultipartEntityBuilder.create().addTextBody("xml", reqXML).build();
                HttpEntity reqEntity = new StringEntity(reqXML, "UTF-8");
                httpPost.setEntity(reqEntity);
                log.info("executing request" + httpPost.getRequestLine(), WxPayTool.class);
                CloseableHttpResponse response = httpclient.execute(httpPost);
                myTryCatch(sb, response);
            } finally {
                httpclient.close();
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 方法名：transfer
     * 详述：企业付款到用户微信余额
     *
     * @param mch_appid        商户appid
     * @param mch_id           商户号
     * @param partner_trade_no 订单号
     * @param openid           用户微信openid
     * @param re_user_name     实名姓名
     * @param amount           金额（分）
     * @param desc             企业付款描述信息
     * @return
     */
    public static String transfer(String mch_appid, String mch_id, String partner_trade_no, String openid, String re_user_name, int amount, String desc) {
        try {
            StringBuilder sb = new StringBuilder();
            SortedMap<String, Object> sp = new TreeMap<String, Object>();
            sp.put("mch_appid", mch_appid);
            sp.put("mchid", mch_id);
            sp.put("nonce_str", MD5Tool.encryptString(System.currentTimeMillis() / 1000 + ""));
            sp.put("partner_trade_no", partner_trade_no);
            sp.put("openid", openid);
            sp.put("check_name", "NO_CHECK");
            if (StringUtils.isNotEmpty(re_user_name)) {
                sp.put("check_name", "FORCE_CHECK");
                sp.put("re_user_name", re_user_name);
            }
            sp.put("amount", amount);//企业付款金额，单位为分
            sp.put("desc", desc);
            sp.put("spbill_create_ip", IpUtils.getHostIp().replace("http://", ""));
            sp.put("sign", SignTool.signApp(sp));
            String reqXML = XMLTool.mapToXML(sp);
            log.info("--- transfer() reqXML:\n" + reqXML, WxPayTool.class);
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            FileInputStream instream = new FileInputStream(new File(WxConfig.path_cert));
            try {
                keyStore.load(instream, mch_id.toCharArray());
            } finally {
                instream.close();
            }
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext,
                    new String[]{"TLSv1"},
                    null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .build();
            try {
                HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers");
                HttpEntity reqEntity = new StringEntity(reqXML, "UTF-8");
                httpPost.setEntity(reqEntity);
                log.info("executing request" + httpPost.getRequestLine(), WxPayTool.class);
                CloseableHttpResponse response = httpclient.execute(httpPost);
                myTryCatch(sb, response);
            } finally {
                httpclient.close();
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 方法名：getTransferInfo
     * 详述：企业付款结果查询
     *
     * @param appid            商户appid
     * @param mch_id           商户号
     * @param partner_trade_no 订单号
     * @return
     */
    public static String getTransferInfo(String appid, String mch_id, String partner_trade_no) {
        try {
            StringBuilder sb = new StringBuilder();
            SortedMap<String, Object> sp = new TreeMap<String, Object>();
            sp.put("appid", appid);
            sp.put("mch_id", mch_id);
            sp.put("nonce_str", MD5Tool.encryptString(System.currentTimeMillis() / 1000 + ""));
            sp.put("partner_trade_no", partner_trade_no);
            sp.put("sign", SignTool.signApp(sp));
            String reqXML = XMLTool.mapToXML(sp);
            log.info("--- refund() reqXML:\n" + reqXML, WxPayTool.class);
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            FileInputStream instream = new FileInputStream(new File(WxConfig.path_cert));
            try {
                keyStore.load(instream, mch_id.toCharArray());
            } finally {
                instream.close();
            }
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext,
                    new String[]{"TLSv1"},
                    null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .build();
            try {
                HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo");
                HttpEntity reqEntity = new StringEntity(reqXML, "UTF-8");
                httpPost.setEntity(reqEntity);
                log.info("executing request" + httpPost.getRequestLine(), WxPayTool.class);
                CloseableHttpResponse response = httpclient.execute(httpPost);
                myTryCatch(sb, response);
            } finally {
                httpclient.close();
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 企业付款到银行卡
     */
    public static String transBank(String mchid, String orderNo, String trueName, String bankNo, String bankCode, int amount, String desc) {
        try {
            StringBuilder sb = new StringBuilder();
            String enc_true_name = RSATool.getRSA(trueName, WxConfig.public_Key_PKCS8);
            String enc_bank_no = RSATool.getRSA(bankNo, WxConfig.public_Key_PKCS8);
            String nonce_str = MD5Tool.encryptString(System.currentTimeMillis() / 1000 + "");
            //获取签名
            SortedMap<String, Object> sp = new TreeMap<>();
            sp.put("mch_id", mchid);
            sp.put("partner_trade_no", orderNo);
            sp.put("nonce_str", nonce_str);
            sp.put("enc_bank_no", enc_bank_no);
            sp.put("enc_true_name", enc_true_name);
            sp.put("bank_code", bankCode);
            sp.put("amount", amount);
            sp.put("desc", desc);
            String sign = SignTool.signApp(sp);
            //请求企业付款
            sp.put("sign", sign);
            String reqXML = XMLTool.mapToXML(sp);
            System.out.println("reqXML : \n" + reqXML);
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            String path_cert = WxConfig.path_cert;
            log.info("--- path_cert:" + path_cert);
            File certFile = new File(path_cert);
            if (certFile == null) {
                log.error("--- certFile is null", WxPayTool.class);
            }
            FileInputStream instream = new FileInputStream(certFile);
            try {
                keyStore.load(instream, WxConfig.weixin_mch_id_app.toCharArray());
            } finally {
                instream.close();
            }
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WxConfig.weixin_mch_id_app.toCharArray()).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext,
                    new String[]{"TLSv1"},
                    null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .build();
            try {
                HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank");
                HttpEntity reqEntity = new StringEntity(reqXML, "UTF-8");
                httpPost.setEntity(reqEntity);
                log.info("executing request" + httpPost.getRequestLine(), WxPayTool.class);
                CloseableHttpResponse response = httpclient.execute(httpPost);
                myTryCatch(sb, response);
            } finally {
                httpclient.close();
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 方法名：getTransBank
     * 详述：企业付款银行卡结果查询
     *
     * @param mch_id            商户号
     * @param partner_trade_no 订单号
     * @return
     */
    public static String getTransBank(String mch_id, String partner_trade_no) {
        try {
            StringBuilder sb = new StringBuilder();
            SortedMap<String, Object> sp = new TreeMap<String, Object>();
            sp.put("mch_id", mch_id);
            sp.put("nonce_str", MD5Tool.encryptString(System.currentTimeMillis() / 1000 + ""));
            sp.put("partner_trade_no", partner_trade_no);
            sp.put("sign", SignTool.signApp(sp));
            String reqXML = XMLTool.mapToXML(sp);
            log.info("--- refund() reqXML:\n" + reqXML, WxPayTool.class);
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            FileInputStream instream = new FileInputStream(new File(WxConfig.path_cert));
            try {
                keyStore.load(instream, mch_id.toCharArray());
            } finally {
                instream.close();
            }
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext,
                    new String[]{"TLSv1"},
                    null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .build();
            try {
                HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/mmpaysptrans/query_bank");
                HttpEntity reqEntity = new StringEntity(reqXML, "UTF-8");
                httpPost.setEntity(reqEntity);
                log.info("executing request" + httpPost.getRequestLine(), WxPayTool.class);
                CloseableHttpResponse response = httpclient.execute(httpPost);
                myTryCatch(sb, response);
            } finally {
                httpclient.close();
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 方法名：transRed
     * 详述：发红包
     *
     * @param wxappid       公众账号appid
     * @param mch_id        商户号
     * @param mch_billno    商户订单号
     * @param scene_id      场景id
     * @param openid        用户openid
     * @param send_name     商户名称
     * @param amount        红包金额
     * @param act_name      活动名称
     * @param wishing       红包祝福语
     * @param remark        备注
     * @return
     */

    public static String transRed(String wxappid, String mch_id, String mch_billno, String scene_id, String openid, String send_name, int amount, String act_name, String wishing, String remark) {
        try {
            StringBuilder sb = new StringBuilder();
            SortedMap<String, Object> sp = new TreeMap<String, Object>();
            sp.put("wxappid", wxappid);
            sp.put("mch_id", mch_id);
            sp.put("nonce_str", MD5Tool.encryptString(System.currentTimeMillis() / 1000 + ""));
            sp.put("mch_billno", mch_billno);
            sp.put("re_openid", openid);
            sp.put("send_name", send_name);
            sp.put("total_amount", amount);//金额，单位为分
            sp.put("total_num", 1); //红包发放总人数
            sp.put("remark", remark);
            sp.put("client_ip", IpUtils.getHostIp().replace("http://", ""));
            sp.put("wishing", wishing);
            sp.put("act_name", act_name);
            sp.put("scene_id", scene_id);
            sp.put("sign", SignTool.signApp(sp));
            String reqXML = XMLTool.mapToXML(sp);
            log.info("--- transRed() reqXML:\n" + reqXML, WxPayTool.class);
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            FileInputStream instream = new FileInputStream(new File(WxConfig.path_cert));
            try {
                keyStore.load(instream, mch_id.toCharArray());
            } finally {
                instream.close();
            }
            SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, mch_id.toCharArray()).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                    sslcontext,
                    new String[]{"TLSv1"},
                    null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            CloseableHttpClient httpclient = HttpClients.custom()
                    .setSSLSocketFactory(sslsf)
                    .build();
            try {
                HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack");
                HttpEntity reqEntity = new StringEntity(reqXML, "UTF-8");
                httpPost.setEntity(reqEntity);
                log.info("executing request" + httpPost.getRequestLine(), WxPayTool.class);
                CloseableHttpResponse response = httpclient.execute(httpPost);
                myTryCatch(sb, response);
            } finally {
                httpclient.close();
            }
            Document doc = XMLTool.strToXMLDocment(sb.toString());
            String result_code = doc.getRootElement().elementText("result_code");
            String return_msg = doc.getRootElement().elementText("return_msg");
            String err_code = doc.getRootElement().elementText("err_code");
            if (!result_code.equals("SUCCESS")) {
                if (StringUtils.isNotEmpty(err_code)) {
                    if (err_code.equals("NOTENOUGH")) {
                        result_code = "发放失败，" + return_msg;
                    } else if (err_code.equals("NO_AUTH")) {
                        result_code = return_msg;
                    } else if (err_code.equals("SENDNUM_LIMIT")) {
                        result_code = "发放失败，" + return_msg;
                    } else {
                        result_code = "发放失败，此请求可能存在风险，已被微信拦截";
                    }
                }
            }
            return result_code;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static void myTryCatch(StringBuilder sb, CloseableHttpResponse response) throws IOException {
        try {
            HttpEntity entity = response.getEntity();
            log.info("----------------------------------------", WxPayTool.class);
            log.info(response.getStatusLine().toString(), WxPayTool.class);
            if (entity != null) {
                log.info("Response content length: " + entity.getContentLength(), WxPayTool.class);
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent()));
                String text;
                while ((text = bufferedReader.readLine()) != null) {
                    sb.append(text);
                    log.info(text, WxPayTool.class);
                }
            }
            EntityUtils.consume(entity);
        } finally {
            response.close();
        }
    }

}
